먼저 데이터의 유무부터 확인하자. fp-ts 라이브러리가 없다면 다음과 같은 함수로 검증을 할 수 있을 것이다.
fp-ts 적용
username 과 password 중 하나라도 없다면 에러를 발생시키고, 아니면 UserInput 타입으로 변환한다.
이 함수에 fp-ts 라이브러리를 적용해 보자.
먼저 에러 대신 Option 타입을 반환하도록 만들어보자.
좀더 눈에 잘 들어오도록 하나하나 작성해보자.
pipe
여기에 pipe 함수를 적용해보자.
그럴듯해 보이지만 주석을 써놓은 곳에 오류가 발생한다.
왜냐면 해당 함수에 들어가는 인자는 Option 타입이기 때문이다.
따라서 다음과 같이 수정해야 한다.
map
이를 O.map 함수를 이용하면 좀더 읽기 좋게 바꿀 수 있다.
통일성을 위해서 username 을 작성하는 곳도 O.map 으로 바꿔보자.
하지만 이렇게만 작성하면 body 가 Option 이 아니기 때문에 오류가 발생한다. O.of 로 body 를 Option 으로 만들어주자.
fromPredicate
그럼 이제는 반복되는 부분을 바꿔보자.
다음과 같은 함수를 만들어보자.
사실 fp-ts/Record 라이브러리에 동일한 작업을 하는 has 함수가 이미 존재한다.
그러나 해당 함수는 key 를 string 으로만 제한하고 있어 PropertyKey 로 바꿔주었다.
이 함수를 이용하면 다음과 같이 작성할 수 있다.
아예 has 함수도 Option 을 반환하도록 만들면 어떨까?
다음과 같이 작성해보자.
잘 보면 해당 함수는 key 가 obj 에 존재하는지를 확인 하는 부분과 실제로 반환 값을 만드는 부분으로 나눌 수 있다.
이런 상황이 많이 발생하기 때문에 fp-ts 에서는 fromPredicate 함수를 제공한다.
더 나아가, 이렇게 되면 obj 인자를 생략할 수 있다.
이를 통해 다음과 같이 작성할 수 있다.
flatMap
하지만 이렇게 되면 함수에 오류가 난다. Option 이 중복되어 Option<Option<Option<any>>> 가 되기 때문이다.
O.flatten 함수를 이용해서 Option 을 하나로 만들어주자.
너무 길어지는 듯 보인다.
사실 잘 보면 has4 는 Option 을 받아 Option 컨테이너 속 값을 까보고 확인할 수 있다.
이는 여기에 쓰인 O.fromPredicate 함수가 O.map 의 역할을 하기 때문이다.
그럼 O.flatten 과 O.map 을 합친 O.flatMap 을 이용하면 좀더 간결하게 만들 수 있지 않을까?
이를 이용해 has 함수를 다시 작성해보자.
그럼 다음과 같이 작성할 수 있다.
최종 코드
최종적으로 다음과 같은 코드를 작성할 수 있다.
잘 작동하는지 다음과 같은 테스트 코드로 검증해보자.
잘 작동하는 것을 확인할 수 있다.
추가로 has 함수를 작성할 때 사용한 O.flatMap(O.fromPredicate(pred)); 부분이 데이터를 검증할 때 많이 사용될 것 같다.
그래서 다음과 같은 함수를 미리 만들어 보았다. 공식문서를 찾아보면 비슷한 함수가 이미 있을 것 같기도 하다.
Predicate 는 fp-ts 에서 제공하는 타입이다. type Predicate<A> = (a: A) => a is A, 인자가 어떤 타입인지를 보장하는 함수이다.
찾아보니 fp-ts/Option 의 filter 함수가 있었다.
해당 함수에 대한 설명은 다음 글에서 이어가도록 하겠다.